package cs.ubbcluj.ro.mps.bridge.implementation;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import cs.ubbcluj.ro.datatypes.implementations.NativeMatrix;
import cs.ubbcluj.ro.datatypes.implementations.NativeVector;
import cs.ubbcluj.ro.datatypes.interfaces.Matrix;
import cs.ubbcluj.ro.datatypes.interfaces.Vector;
import cs.ubbcluj.ro.mps.bridge.interfaces.MpsImpInterface;
import cs.ubbcluj.ro.mps.data.ConstrainType;
import cs.ubbcluj.ro.mps.data.MpsImpl;
import cs.ubbcluj.ro.mps.data.interfaces.Constrain;
import cs.ubbcluj.ro.mps.data.interfaces.Mps;

public class NativeMpsImp implements MpsImpInterface{

	Mps theMps;
	 
	public NativeMpsImp(Mps mps){
		theMps=mps;
	}
	
	public NativeMpsImp(){}
	
	public Matrix getCoefficients() {
		
	    	final Collection<Constrain> constrainList = theMps.getConstrains().values();

	    	final int count = theMps.countLGConstrains();
	    	

	    	final Matrix coef = new NativeMatrix(theMps.getConstrains().values().size(),theMps.getNumberOfVariables()+ count);
	    	int i = -1;
	    	int j = -1;
	    	int k = 0;
	    	for (final Constrain constrain : constrainList) {
	    	    j = -1;
	    	    ++i;
	    	    for (final Iterator<String> variableNameIterator = theMps.getVariableIndex()
	    		    .iterator(); variableNameIterator.hasNext();) {
	    		final String variableName = variableNameIterator.next();
	    		if (constrain.containsVariable(variableName)) {
	    		    coef.addElement(i, ++j, constrain.getCoefficient(variableName));
	    		} else {
	    			coef.addElement(i, ++j, 0);
	    		}
	    	    }
	    	    switch (constrain.getType()) {
	    	    case L: {
	    	    coef.addElement(i, theMps.getNumberOfVariables()+ k, 1);
	    		k++;
	    		break;
	    	    }
	    	    case G: {
	    	    coef.addElement(i, theMps.getNumberOfVariables() + k, -1);
	    		k++;
	    		break;
	    	    }
	    	    default: {

	    	    }
	    	    }
	    	}

	    	return coef;
	        
	}

	
	public Vector getRightHandSideValues() {
		Map<String, Double> rhsValues = new HashMap<String, Double>();
		final Iterator<Map<String, Double>> iterator = theMps.getRhs().values()
			.iterator();
		if (iterator.hasNext()) {
		    rhsValues = iterator.next();
		}
		
		final Vector b = new NativeVector(theMps.getConstrains().size());
		int i = -1;
		for (final String constrainName : theMps.getConstrains().keySet()) {
		    if (rhsValues.containsKey(constrainName)) {
			b.addElement(++i, rhsValues.get(constrainName));
		    } else {
			b.addElement(++i, 0f);
		    }
		}

		return b;
		
	}

	public Vector getTargetCoefficients() {

		final int count = theMps.countLGConstrains();

		final Vector c = new NativeVector(theMps.getNumberOfVariables() + count);
		final Map<String, Double> variables = theMps.getTargetFunction().values()
			.iterator().next().getVariables();

		int i = -1;
		for (final Iterator<String> variableNameIterator = theMps.getVariableIndex()
			.iterator(); variableNameIterator.hasNext();) {
		    final String variableName = variableNameIterator.next();
		    if (variables.containsKey(variableName)) {
			c.addElement(++i, variables.get(variableName));
		    } else {
			c.addElement(++i, 0);
		    }
		}

		return c;
	}	
	

	
	public Vector getLowerBounds() {
		final Vector lowerBounds = new NativeVector(theMps.getNumberOfVariables());

		int i = -1;
		for (final Iterator<String> variableNameIterator = theMps.getVariableIndex()
			.iterator(); variableNameIterator.hasNext();) {
		    final String variableName = variableNameIterator.next();
		    if (theMps.getLowerBound().containsKey(variableName)) {
			lowerBounds.addElement(++i, theMps.getLowerBound().get(variableName));
		    } 
		    else {
			lowerBounds.addElement(++i, 0);
		    }
		}

		return lowerBounds;
	}

	@Override
	public Vector getUpperBounds() {
		final Vector upperBounds = new NativeVector(theMps.getNumberOfVariables());

		int i = -1;
		for (final Iterator<String> variableNameIterator = theMps.getVariableIndex()
			.iterator(); variableNameIterator.hasNext();) {
		    final String variableName = variableNameIterator.next();
		    if (theMps.getUpperBound().containsKey(variableName)) {
			upperBounds.addElement(++i, theMps.getUpperBound().get(variableName));
		    } else {
			upperBounds.addElement(++i, 1000000d); // plus infinit
		    }
		}

		return upperBounds;
	}
	
	
	/*
	 public double[] getRangesLowerLimit() {
	Map<String, Double> rangesValues = new HashMap<String, Double>();
	final Iterator<Map<String, Double>> iterator = this.ranges.values()
		.iterator();
	if (iterator.hasNext()) {
	    rangesValues = iterator.next();
	}

	Map<String, Double> rhsValues = new HashMap<String, Double>();
	final Iterator<Map<String, Double>> iteratorRhs = this.rhs.values()
		.iterator();
	if (iterator.hasNext()) {
	    rhsValues = iterator.next();
	}

	final double[] lowerLimits = new double[this.constrains.size()];
	int i = -1;
	for (final String constrainName : this.constrains.keySet()) {
	    if (rangesValues.containsKey(constrainName)) {
		Double rhsVal = rhsValues.get(constrainName);
		if (rhsVal == null) {
		    rhsVal = 0d;
		}
		if (this.constrains.get(constrainName).getType() == ConstrainType.L) {
		    lowerLimits[++i] = rhsVal
			    - Math.abs(rangesValues.get(constrainName));
		} else {
		    if (this.constrains.get(constrainName).getType() == ConstrainType.E
			    && rangesValues.get(constrainName) < 0) {
			lowerLimits[++i] = rhsVal
				+ rangesValues.get(constrainName);
		    } else {
			lowerLimits[++i] = rhsVal;
		    }
		}

	    } else {
		lowerLimits[++i] = Double.MIN_VALUE;
	    }
	}

	return lowerLimits;
    }

    @Override
    public double[] getRangesUpperLimit() {
	Map<String, Double> rangesValues = new HashMap<String, Double>();
	final Iterator<Map<String, Double>> iterator = this.ranges.values()
		.iterator();
	if (iterator.hasNext()) {
	    rangesValues = iterator.next();
	}

	Map<String, Double> rhsValues = new HashMap<String, Double>();
	final Iterator<Map<String, Double>> iteratorRhs = this.rhs.values()
		.iterator();
	if (iterator.hasNext()) {
	    rhsValues = iterator.next();
	}

	final double[] upperLimits = new double[this.constrains.size()];
	int i = -1;
	for (final String constrainName : this.constrains.keySet()) {
	    Double rhsVal = rhsValues.get(constrainName);
	    if (rhsVal == null) {
		rhsVal = 0d;
	    }
	    if (rangesValues.containsKey(constrainName)) {
		if (this.constrains.get(constrainName).getType() == ConstrainType.G) {
		    upperLimits[++i] = rhsVal
			    + Math.abs(rangesValues.get(constrainName));
		} else {
		    if (this.constrains.get(constrainName).getType() == ConstrainType.E
			    && rangesValues.get(constrainName) > 0) {
			upperLimits[++i] = rhsVal
				+ rangesValues.get(constrainName);
		    } else {
			upperLimits[++i] = rhsVal;
		    }
		}

	    } else {
		upperLimits[++i] = rhsVal;
	    }
	}

	return upperLimits;
    }
	 */ 
	public void setTheMps(Mps mps) {
		this.theMps=mps;
	} 
}
